package com.cvte.vdt.uartservice.util;

import java.io.UnsupportedEncodingException;
import java.nio.charset.StandardCharsets;
import java.util.Queue;
import java.util.StringTokenizer;
import java.util.concurrent.ArrayBlockingQueue;

/**
 * Created by wuguitong on 2018/11/21.
 */
public class DataUtil {
    private static final String TAG = "DataUtil";
    public static final String DATA = "Data";
    public static final String COMMAND = "CommandREC";
    public static final String DEFAULT_MAC = "";
    public static final String DEFAULT_NAME = "";
    public static final String DEF_SEND_VER = "";
    public static final String DEF_REC_VER = "";
    public static final String DEF_MUSIC_NAME = "";
    public final static int BT_PAIR = 1;
    public final static int BT_NOT_PAIR = 0;

    public static final byte MUSIC_PLAY_SENDMODE = (byte)0x01;
    public static final byte MUSIC_PAUSE_SENDMODE = (byte)0x02;
    public static final byte MUSIC_STOP_SENDMODE = (byte)0x03;
    public static final byte MUSIC_PRE_SENDMODE = (byte)0x04;
    public static final byte MUSIC_NEXT_SENDMODE = (byte)0x05;

    /*head code*/
    private static final byte HEAD_CODE_SEND = (byte)0x55;
    private static final byte HEAD_CODE_REC = (byte)0xff;
    /*end code*/
    private static final byte LAST_END_CODE = (byte)0x0a;
    private static final byte SECOND_LAST_END_CODE = (byte)0x0d;
    /*mode*/
    public static final byte COMMAND_RESET = (byte)0x70;
    public static final byte COMMAND_SELECT_REC_MODE = (byte)0x71;
    public static final byte COMMAND_SELECT_SEND_MODE = (byte)0x72;
    public static final byte COMMAND_POWER_ONOFF = (byte)0x73;
    public static final byte COMMAND_GET_CUR_MODE = (byte)0x74;
    public static final byte COMMAND_CLEAN_INFO = (byte)0x75;

    public static final byte RESULT_POWER_REMIND = (byte)0x10;
    public static final byte RESULT_REC_MODE_INIT = (byte)0x11;
    public static final byte RESULT_SEND_MODE_INIT = (byte)0x12;
    public static final byte RESULT_POWER_STATUS = (byte)0x13;
    public static final byte RESULT_CUR_MODE = (byte)0x14;
    /*send mode*/
    public static final byte COM_SEND_SEARCH = (byte)0x01;
    public static final byte COM_SEND_CANEL_SEARCH = (byte)0x02;
    public static final byte COM_SEND_DELETE_DEVICE = (byte)0x03;
    public static final byte COM_SEND_CONNECT_DEVICE = (byte)0x04;
    public static final byte COM_SEND_CANEL_CONNECT = (byte)0x05;
    public static final byte COM_SEND_SET_VOLUME = (byte)0x06;
    public static final byte COM_SEND_A2DP_STATUS = (byte)0x07;
    public static final byte COM_SEND_GET_NAME = (byte)0x08;
    public static final byte COM_SEND_GET_VERSION = (byte)0x09;

    public static final byte RES_SEND_SEARCH_FIND = (byte)0x67;
    public static final byte RES_SEND_SEARCH_END =  (byte)0x68;
    public static final byte RES_SEND_PAIR_SUC = (byte)0x69;
    public static final byte RES_SEND_SET_VOLUME = (byte)0x6a;
    public static final byte RES_SEND_A2DP_CON_SUC = 0x6b;
    public static final byte RES_SEND_A2DP_CON_FAIL = (byte)0x6c;
    public static final byte RES_SEND_A2DP_CON_CANEL = (byte)0x6d;
    public static final byte RES_SEND_A2DP_STATUS = (byte)0x6e;
    public static final byte RES_SEND_GET_NAME = (byte)0x6f;
    public static final byte RES_SEND_GET_VERSION = (byte)0x70;
    public static final byte RES_SEND_POWER_STATUS = (byte)0x71;
    public static final byte RES_SEND_GET_ACTION = (byte)0x72;


    public static final byte DATA_SEND_A2DP_STATUS_READY = (byte)0x00;
    public static final byte DATA_SEND_A2DP_STATUS_CONNECTED = (byte)0x01;
    public static final byte DATA_SEND_A2DP_STATUS_STREAMING = (byte)0x02;
    public static final byte DATA_SEND_A2DP_STATUS_PAUSED = (byte)0x03;
    /*rec mode*/
    public static final byte COM_REC_PAIR = (byte)0x81;
    public static final byte COM_REC_DELETE_DEVICE = (byte)0x82;
    public static final byte COM_REC_CANEL_CONNECT = (byte)0x83;
    public static final byte COM_REC_CONNECT_DEVICE = (byte)0x84;
    public static final byte COM_REC_MUSIC_ACTION = (byte)0x85;
    public static final byte COM_REC_SET_VOLUME = (byte)0x86;
    public static final byte COM_REC_GET_VOLUME = (byte)0x87;
    public static final byte COM_REC_GET_A2Dp_STATUS = (byte)0x88;
    public static final byte COM_REC_GET_NAME = (byte)0x89;
    public static final byte COM_REC_GET_VERSION = (byte)0x8a;

    public static final byte RES_REC_PAIR_SUC = (byte)0x91;
    public static final byte RES_REC_SET_VOLUME = (byte)0x92;
    public static final byte RES_REC_A2DP_CONNECT_SUC = (byte)0x93;
    public static final byte RES_REC_A2DP_CONNECT_FAIL = (byte)0x94;
    public static final byte RES_REC_A2DP_CANEL_CONNECT = (byte)0x95;
    public static final byte RES_REC_A2DP_STATUS = (byte)0x96;
    public static final byte RES_REC_CUR_MUSIC_NAME = (byte)0x97;
    public static final byte RES_REC_GET_NAME = (byte)0x98;
    public static final byte RES_REC_GET_VERSION = (byte)0x99;

    public static final byte DATA_REC_A2DP_STATUS_READY = (byte)0x00;
    public static final byte DATA_REC_A2DP_STATUS_CONNECTED = (byte)0x01;
    public static final byte DATA_REC_A2DP_STATUS_STREAMING = (byte)0x02;

    public static final byte RESULT_REC_UNKNOW = (byte)0x00;


    private static byte[] receBuff;
    private static int buffCurrentSize;
    public static Queue<ReceData> receDataQueue;

    public static void initSerialDataUtil() {
        buffCurrentSize = 0;
        receBuff = new byte[1024];
        receDataQueue = new ArrayBlockingQueue<ReceData>(10);
    }
    public static void deinitSerialDataUtil() {
        buffCurrentSize = 0;
        receBuff = null;
        receDataQueue = null;
    }
    public static class ReceData {
        private byte commandId = RESULT_REC_UNKNOW;
        private byte[] data = null;
        public void setCommandId(byte commandId) {
            this.commandId = commandId;
        }
        public void setReceData(byte[] bytes) {
            data = new byte[bytes.length];
            System.arraycopy(bytes, 0, data, 0, bytes.length);
        }


        public byte getCommandId() {
            return this.commandId;
        }

        public byte[] getReceData() {
            return data;
        }
    }
    public static int decodeReceBuff(byte[] buff, int size) {
        int count = 0;
        if (addReceBuff(buff, size)) {
            ReceData data = decodeData();
            while (data != null) {
                receDataQueue.offer(data);
                count++;
                data = decodeData();
            }
            return count;
        } else {
            return 0;
        }
    }
    private static ReceData decodeData() {
        ReceData data = null;
        boolean isDecodeSuccess = false;
        short length = 0;
        short datalength = 0;
        int startIndex = 0;
        int endIndex = 0;
        byte command = RESULT_REC_UNKNOW;
        for (int i = 0; i < buffCurrentSize; i++) {
            if (receBuff[i] == HEAD_CODE_REC) {
                startIndex = i;
                if ((buffCurrentSize >= i + 5)) {
                    datalength = receBuff[i+1];
                    if ( (buffCurrentSize >= (datalength + i + 4))) {
                        length = (short)(datalength + 4);
                        command = receBuff[i+2];
                        if (receBuff[i + 2 + datalength] == SECOND_LAST_END_CODE && receBuff[i + 3 + datalength] == LAST_END_CODE) {
                            isDecodeSuccess = true;
                            endIndex = startIndex + length;
                        }
                    }
                }
            }
            if (isDecodeSuccess) {
                data = new ReceData();
                data.setCommandId(command);
                if(datalength >= 2) {
                    byte[] valueBytes = new byte[datalength - 1];
                    System.arraycopy(receBuff, startIndex + 3, valueBytes, 0, datalength - 1);
                    data.setReceData(valueBytes);
                }
                buffCurrentSize -= endIndex;
                byte[] tembytes = new byte[buffCurrentSize];
                System.arraycopy(receBuff, endIndex, tembytes, 0, buffCurrentSize);
                System.arraycopy(tembytes, 0, receBuff, 0, buffCurrentSize);
                return data;
            }
        }
        return data;
    }
    private static boolean addReceBuff(byte[] buff, int size) {
        if (buffCurrentSize + size < 1024) {
            System.arraycopy(buff, 0, receBuff, buffCurrentSize, size);
            buffCurrentSize += size;
            return true;
        } else {
            buffCurrentSize = 0;
            return false;
        }
    }
    public static ReceData getCurrentReceData() {
        return receDataQueue.poll();
    }

    public static byte[] getComBuff(byte command){
        return getSendDataCodeBuf(command,null);
    }

    public static byte[] getComBuff(byte command, byte[] dataBuf){
        return getSendDataCodeBuf(command,dataBuf);
    }

    public static byte[] getSendDataCodeBuf(byte command, byte[] dataBuf) {
        byte[] bytearray;
        int length = 0;
        int dataBufSize = 0;
        if(dataBuf == null) {
            length = 1;
            dataBufSize = 0;
        }else{
            dataBufSize = dataBuf.length;
            length = (byte) (dataBufSize + 1);
        }
        bytearray = new byte[length + 4];
        bytearray[0] = HEAD_CODE_SEND;
        bytearray[1] = (byte)length;
        bytearray[2] = command;
        for (int i = 0; i < dataBufSize; i++) {
            bytearray[3 + i] = dataBuf[i];
        }
        bytearray[length + 2] = SECOND_LAST_END_CODE;
        bytearray[length + 3] = LAST_END_CODE;
        return bytearray;

    }

    public static String byteArrayToStr(byte[] byteArray) {
        if (byteArray == null) {
            return null;
        }
        String str = new String(byteArray,StandardCharsets.UTF_8);
        return str;
    }

    public static byte[] strToByteArray(String str){
        if(str == null){
            return null;
        }
        byte[] bytes  = str.getBytes(StandardCharsets.UTF_8);
        return bytes;
    }

    private static final char[] hexCode = "0123456789ABCDEF".toCharArray();
    public static String printHexBinary(byte[] data) {
        if(data == null){
            return "NULL";
        }
        StringBuilder r = new StringBuilder(data.length * 5);
        for (byte b : data) {
            r.append('0');
            r.append('X');
            r.append(hexCode[(b >> 4) & 0xF]);
            r.append(hexCode[(b & 0xF)]);
            r.append(' ');
        }
        return r.toString();
    }

}
